package fr.paris.lutece.plugins.${plugin.name}.business.dao;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import fr.paris.lutece.plugins.${bean.pluginName}.commons.ResultList;
import fr.paris.lutece.portal.service.jpa.JPALuteceDAO;

/**
 * The abstract class for all DAO
 * @author ${bean.author}
 */
public class Abstract${bean.pluginName?cap_first}DAO<K, E> extends JPALuteceDAO<K, E> implements I${bean.pluginName?cap_first}DAO<K,E> {

	/**
	 * Generate count query from criteria query and return a paged query.
	 * 
	 * @param <T> the generic type of criteria query
	 * @param criteriaQuery criteria query
	 * @param paginationProperties pagination data
	 * @return query paged
	 */
	protected <T> PagedQuery createPagedQuery(CriteriaQuery<T> criteriaQuery, PaginationProperties paginationProperties) {

		// Generate count query
		EntityManager em = getEM();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
		countQuery.select(cb.count(countQuery.from(criteriaQuery.getResultType())));

		countQuery.getRoots().clear();
		for (Root<?> root : criteriaQuery.getRoots()) {
			countQuery.getRoots().add(root);
		}

		if (criteriaQuery.getRestriction() != null) {
			countQuery.where(criteriaQuery.getRestriction()).distinct(true);
		}

		// Create the paged query
		PagedQuery pq = new PagedQuery(em.createQuery(criteriaQuery), em.createQuery(countQuery), paginationProperties);

		return pq;
	}

	/**
	 * Return all entities paged.
	 * 
	 * @param paginationProperties properties for pagination
	 * @return the result list
	 */
	public ResultList<E> findAll(PaginationProperties paginationProperties) {

		Query query = getEM().createQuery("SELECT e FROM " + getEntityClassName() + " e ");

		Query countQuery = getEM().createQuery("SELECT count(e) FROM " + getEntityClassName() + " e ");

		PagedQuery pq = new PagedQuery(query, countQuery, paginationProperties);
		return pq.getResultList();
	}

	/**
	 * Add a predicate to an existing query
	 * 
	 * @param query existing query
	 * @param exp restriction
	 */
	protected void addRestriction(CriteriaQuery<?> query, Expression<Boolean> exp) {
		CriteriaBuilder builder = getEM().getCriteriaBuilder();
		Predicate restriction = query.getRestriction();
		if (restriction == null) {
			query.where(exp);
		} else {
			query.where(builder.and(restriction, exp));
		}
	}

	@Override
	public String getPluginName() {
		
		return "${bean.pluginName}";
	}
	
	    
    /**
     * Add the order by parameter to the query.
     * 
     * @param filter the filter
     * @param root the offer root
     * @param query the criteria query
     * @param builder the criteria builder
     */
    protected void buildSortQuery( Filter filter, Root<Bean> root, CriteriaQuery<Bean> query,
    	CriteriaBuilder builder )
    {
    	if ( filter.getOrders( ) != null && !filter.getOrders( ).isEmpty( ) )
    	{
    	    List<Order> orderList = new ArrayList<Order>( );

    	    	// get asc order
    	    	for ( String order : filter.getOrders( ) )
    	    	{
		    	    if ( filter.isOrderAsc(  ) )
					{
						orderList.add( builder.asc( root.get( order ) ) );
					}
				}

    	    query.orderBy( orderList );
    	}
    }
}
